﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;

namespace IndexedList
{
    public class ListIndex<T> : BaseListIndex<T> where T : new()
    {
        Dictionary<int, List<T>> IndexData = new Dictionary<int, List<T>>();

        public ListIndex(ISet<string> fieldNames)
            : base(fieldNames)
        {
        }

        public ListIndex(Expression<Func<T, object>> expression)
            : base(expression)
        {
        }

        public ListIndex(string name, Expression<Func<T, object>> expression)
            : base(name, expression)
        {
        }

        public ListIndex(string name, HashSet<string> fieldNames)
            : base(name, fieldNames)
        {
        }

        public override void IndexItem(T data)
        {
            List<T> IndexPosition = new List<T>();
            int Key = ItemHashFunction(data);
            if (!IndexData.ContainsKey(Key))
                IndexData.Add(Key, IndexPosition);
            else
            {
                IndexPosition = IndexData[Key];
                foreach (var fieldinfo in this.IndexFields.Values)
                {
                    if (!Equals(fieldinfo.GetValue(IndexPosition.First(), null), fieldinfo.GetValue(data, null)))
                    {
                        throw new Exception("Duplicate hash found in data");
                    }
                }
            }
            IndexPosition.Add(data);
        }

        protected override IEnumerable<T> FindItems(int key)
        {
            if (!IndexData.ContainsKey(key))
                return new List<T>();
            return IndexData[key];
        }

        public override void ClearIndexData()
        {
            this.IndexData.Clear();
        }

        public override void RemoveIndex(T item)
        {
            int key = this.ItemHashFunction(item);
            if (this.IndexData.ContainsKey(key))
                this.IndexData.Remove(key);
        }

        protected override T FindSingleItem(int key)
        {
            if (!IndexData.ContainsKey(key))
                return default(T);
            return IndexData[key].FirstOrDefault();
        }
    }

    public static class ListIndexExtensionMethods
    {
        public static void AddIndex<T>(this IList<T> list, Expression<Func<T, object>> expression, string name = "") where T : new()
        {
            IIndexedList<T> indexedlist = list as IIndexedList<T>;
            if (indexedlist != null)
                indexedlist.AddIndex(new ListIndex<T>(expression));
        }

        public static IndexedList<TSource> ToIndexList<TSource>(this IEnumerable<TSource> source) where TSource : new()
        {
            IndexedList<TSource> indexedList = new IndexedList<TSource>();
            foreach (TSource item in source)
            {
                indexedList.Add(item);
            }
            return indexedList;
        }
    }
}
